#include <unistd.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <pthread.h>
#include <time.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "slog.h"
#include "config.h"

static int log_fd = -1;
static pthread_mutex_t log_lock;
int InitialLog(const char * filename )
{
	pthread_mutex_init(&log_lock, NULL);
	log_fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH );
	if ( log_fd < 0 )
	{
		printf("open log file error! errno is %d\n", errno);
		printf("log file name is %s\n", filename);
		return 0;
	}
	return 1;
}

void UninitialLog()
{
	pthread_mutex_lock(&log_lock);
	close(log_fd);
	pthread_mutex_unlock(&log_lock);
	
	pthread_mutex_destroy(&log_lock);
}

static inline void my_write( const char * s, int n )
{
	int ret = 0;
	pthread_mutex_lock(&log_lock);
	ret = write(log_fd, s, n);
	pthread_mutex_unlock(&log_lock);
}

inline void _Out( const char* format, va_list arg, const char * errorMsg )
{
	char buff[MAX_LOG_LINE];
	struct timeval tv;
	int ret, len;
	struct tm gmt;

	gettimeofday( &tv, 0 );	
	localtime_r(&tv.tv_sec, &gmt);
	
	ret = snprintf(buff, MAX_LOG_LINE, "%04d%02d%02d %02d:%02d:%02d.%03ld %s - ",
		gmt.tm_year + 1900, gmt.tm_mon + 1, gmt.tm_mday,  gmt.tm_hour, gmt.tm_min, gmt.tm_sec, tv.tv_usec/1000,
		errorMsg);

	if ( ret >= MAX_LOG_LINE )
	{
		my_write( "!!!!!!!Too Long Line\n", sizeof("!!!!!!!Too Long Line\n")-1 );
	}
	else
	{
		len = ret;
		ret = vsnprintf(buff+len, MAX_LOG_LINE-len, format, arg);
		if ( ret >= MAX_LOG_LINE-len )
		{
			my_write("!!!!!!!Too Long Line!!!!!!!\n", sizeof("!!!!!!!Too Long Line!!!!!!!\n")-1 );
		}
		else if ( MAX_LOG_LINE-len-ret > 1 )
		{
			buff[len+ret] = '\n';
			my_write(buff, len+ret+1);
		}
		else
		{
			my_write(buff, len+ret);
		}
	}
}

void Error( const char* format, ... )
{
	va_list arg;
	va_start( arg, format );
	_Out( format, arg, "ERR");
	va_end(arg);
	FlushLog();
}

void Warn( const char* format, ... )
{
	va_list arg;
	va_start( arg, format );
	_Out( format, arg, "WRN"	);
	va_end(arg);
	FlushLog();
}

void Info( const char* format, ... )
{
	va_list arg;
	va_start( arg, format );
	_Out( format, arg, "INF" );
	va_end(arg);
}

void Debug( const char* format, ... )
{
	va_list arg;
	va_start( arg, format );
	_Out( format, arg,  "DBG" );
	va_end(arg);
}

void FlushLog()
{
	pthread_mutex_lock(&log_lock);
	fsync(log_fd);
	pthread_mutex_unlock(&log_lock);
}
